/* Copyright  2009
   @Author
   Richard Changde Yin            e-mail yinchangde@hotmail.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
 * @filename: bucketList.cc
 */

#include <server_includes.h>
#include<index.h>
#include<allocator.h>
#include<database.h>
#include<debug.h>

#include <util.h>

using namespace BackEnd;

DbRetVal BucketList::insert(Chunk *chunk, Database *db, void *key, void*tuple)
{
    DbRetVal rv = OK;
    HashIndexNode* newNode;
    newNode= (HashIndexNode*) chunk->allocate(db, &rv);
    if (!newNode)
      return rv;

    newNode->ptrToKey_    = key;
    newNode->ptrToTuple_  = tuple;
    newNode->next_        = 0;

    //If this is the first node, set it as head
    if (!head)
    {
      head = tail = newNode;
      newNode->prev = 0;
      ++_size ;
      return OK;
    }
    HashIndexNode *it = tail;
    it->next_ = newNode ;
    newNode->prev = tail;
    tail = newNode;
    ++_size ;
    return rv;
}
BackEnd::DbRetVal BucketList::insertNode(HashIndexNode *newNode)
{
    if (!head)
    {
        head = tail = newNode;
        newNode->prev = 0;
        ++_size ;
        return OK;
    }
    HashIndexNode *it = tail;
    it->next_ = newNode;
    newNode->prev = it;
    newNode->next_= 0;
    tail = newNode;
    ++_size ;
    return OK;
}


BackEnd::DbRetVal BucketList::removeNode(Chunk *chunk, Database *db,HashIndexNode *thenode)
{
    if (!head)
      return BackEnd::ER_NotFound;

    HashIndexNode *ite = head, *prev = head;
      while (ite != NULL)
    {
          if(ite ==  thenode)
        {
            if ( ite == head) {
               if( head == tail )
              {// Oops, only one element in the list
                 tail =ite->next_;
              }
              head = ite->next_;
              chunk->free(db, ite);
              --_size ;
             return BackEnd::OK;
            }
           // not the head.
           prev->next_ = ite->next_;
           if(ite->next_)
             ite->next_->prev = prev ;
           chunk->free(db, ite);
           if(tail == ite)tail = prev ;
            --_size ;
            return OK;
        }
        prev = ite;
        ite = ite->next_;
    }
      return BackEnd::ER_NotFound;
}
//Returns 2 if the head itself is removed.
DbRetVal BucketList::remove(Chunk *chunk, Database *db, void *keyPtr)
{
    if (!head)
    {
      tail = head ;_size=0;
      return BackEnd::ER_NotFound;
    }
    HashIndexNode *ite = head, *prev = head;
    while (ite != NULL)
    {
        if(ite->ptrToKey_ ==  keyPtr)
      {
          if ( ite == head) {
             if( head == tail )
            {// Oops, only one element in the list
               tail =ite->next_;
            }
            head = ite->next_;
            chunk->free(db, ite);
            --_size ;
           return BackEnd::OK;
          }
          prev->next_ = ite->next_;
          if(ite->next_)
            ite->next_->prev = prev ;
          chunk->free(db, ite);
          if(tail == ite)
        {
          tail = prev ;
        }
          --_size ;
          return OK;
      }
      prev = ite;
      ite = ite->next_;
    }
    return BackEnd::ER_NotFound;
}

void BucketList::removeHead(Chunk *chunk, Database *db)
{
    if(head)
  {
    HashIndexNode *ite = head->next_;
    chunk->free(db, head);
    head = ite ;
    if(ite) ite->prev = 0;
    --_size ;
  }else
  {
   tail = head ;
   _size = 0;
  }
}

void BucketList::removeAll (Chunk *chunk, Database *db)
{
    while(_size)
      removeHead(chunk,db);

    head = tail = 0;
    _size= 0 ;
}

HashIndexNode* BucketIter::next()
{
    if (!iter) return NULL;
    HashIndexNode *node = iter;
    iter = iter ->next_;
    return node;
}
